/*******************************************************************
** This code is part of Breakout.
**
** Breakout is free software: you can redistribute it and/or modify
** it under the terms of the CC BY 4.0 license as published by
** Creative Commons, either version 4 of the License, or (at your
** option) any later version.
******************************************************************/
#include "game_level.h"

#include <fstream>
#include <sstream>
#include <vector>

GameLevel::GameLevel(unsigned int levelWidth, unsigned int levelHeight) {
  std::vector<unsigned int> index;
  for (unsigned int i = 0; i < 300; i++) {
    index.push_back(i);
  }
  std::vector<std::vector<unsigned int>> tileData;
  Random::shuffle(index.begin(), index.end());
  for (unsigned int y = 0; y < 15; ++y) {
    std::vector<unsigned int> row;
    for (unsigned int x = 0; x < 20; ++x) {
      row.push_back(0);
    }
    tileData.push_back(row);
  }
  for (unsigned int i = 0; i < index.size(); i++) {
    if (i == 0) {
      tileData[index[i] / 20][index[i] % 20] = 0;
    } else if (i < 200) {
      tileData[index[i] / 20][index[i] % 20] = 1;
    } else if (i < 225) {
      tileData[index[i] / 20][index[i] % 20] = 2;
    } else if (i < 250) {
      tileData[index[i] / 20][index[i] % 20] = 3;
    } else if (i < 275) {
      tileData[index[i] / 20][index[i] % 20] = 4;
    } else {
      tileData[index[i] / 20][index[i] % 20] = 5;
    }
  }
  this->init(tileData, levelWidth, levelHeight);
};

void GameLevel::Draw(SpriteRenderer &renderer) {
  for (GameObject &tile : this->Bricks)
    if (!tile.Destroyed)
      tile.Draw(renderer);
}

bool GameLevel::IsCompleted() {
  for (GameObject &tile : this->Bricks)
    if (!tile.IsSolid && !tile.Destroyed)
      return false;
  return true;
}

void GameLevel::init(std::vector<std::vector<unsigned int>> tileData,
                     unsigned int levelWidth, unsigned int levelHeight) {
  // calculate dimensions
  unsigned int height = tileData.size();
  unsigned int width =
      tileData[0].size(); // note we can index vector at [0] since this function
                          // is only called if height > 0
  float unit_width = levelWidth / static_cast<float>(width),
        unit_height = levelHeight / static_cast<float>(height);
  // initialize level tiles based on tileData
  for (unsigned int y = 0; y < height; ++y) {
    for (unsigned int x = 0; x < width; ++x) {
      // check block type from level data (2D level array)
      if (tileData[y][x] == 1) // solid
      {
        glm::vec2 pos(unit_width * x, unit_height * y);
        glm::vec2 size(unit_width, unit_height);
        GameObject obj(pos, size, ResourceManager::GetTexture("block_solid"),
                       glm::vec3(0.8f, 0.8f, 0.7f));
        obj.IsSolid = true;
        this->Bricks.push_back(obj);
      } else if (tileData[y][x] >
                 1) // non-solid; now determine its color based on level data
      {
        glm::vec3 color = glm::vec3(1.0f); // original: white
        if (tileData[y][x] == 2)
          color = glm::vec3(0.2f, 0.6f, 1.0f);
        else if (tileData[y][x] == 3)
          color = glm::vec3(0.0f, 0.7f, 0.0f);
        else if (tileData[y][x] == 4)
          color = glm::vec3(0.8f, 0.8f, 0.4f);
        else if (tileData[y][x] == 5)
          color = glm::vec3(1.0f, 0.5f, 0.0f);

        glm::vec2 pos(unit_width * x, unit_height * y);
        glm::vec2 size(unit_width, unit_height);
        this->Bricks.push_back(
            GameObject(pos, size, ResourceManager::GetTexture("block"), color));
      }
    }
  }
}